var curry = function (fn) {
    var curryFn = function (...args) {
        if (args.length >= fn.length) {
            return fn(...args)
        } else {
            return (...params) => {
                return curryFn(...[...args, ...params])
            }
        }
    }
    return curryFn
}
const a = (a, b, c, d) => a + b + c + d
const fn = curry(a)
console.log(fn(1, 2)(2, 4))


var currySum = function (...args) {
    let arr = args
    var curryFn = function (...params) {
        arr = arr.concat(params)
        return curryFn
    }
    curryFn.toString = function () {
        return arr.reduce((pre, cur) => pre + cur, 0)
    }
    return curryFn
}
console.log(currySum(1, 2, 3, 4)(5)(6, 7).toString())



var compose = function (...fns) {
    return (val) => {
        return fns.reduceRight((pre, cur) => cur(pre), val)
    }
}
var fn1 = (a) => a + a
var fn2 = (a) => a * a
console.log(fn2(fn1(4)))
console.log(compose(fn2, fn1)(4))



function debounce(fn, delay) {
    let timer = null
    return (...args) => {
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
            fn.apply(this, args)
            timer = null
        }, delay)
    }
}



function debounce2(fn, delay, immediate) {
    let timer = null
    return (...args) => {
        if (timer) clearTimeout(timer)
        if (immediate) {
            if(!timer) fn.apply(this, args)
            timer = setTimeout(() => {
                timer = null
            }, delay)
        } else {
            timer = setTimeout(() => {
                fn.apply(this, args)
                timer = null
            }, delay)
        }
    }
}


function throttle (fn, delay){
    let timer = null
    return (...args) => {
        if(timer) return;
        timer = setTimeout(() => {
            fn.apply(this, args)
            timer = null
        }, delay)
    }
}

function throttle2(fn, delay){
    let timer = null
    let start = Date.now()
    return (...args) => {
        let end = Date.now()
        let wait = delay - (end - start)
        if(wait <= 0){
            if(timer){
                clearTimeout(timer)
                timer = null
            }
            fn.apply(this, args)
            start = Date.now()
        } else {
            if(timer) return;
            timer = setTimeout(() => {
                fn.apply(this, args)
                timer = null
                start = Date.now()
            }, wait)
        }
    }
}